# item_attribute.py

import os
import codecs
import re
import time

####################################################################
#
# Core Behavior
# 
#####################################################################

AUTHOR = 'Grisson'

class CoreError(Exception):
    pass

class FaultError(CoreError):
    pass

class ParseError(CoreError):
    pass

DEFAULT_ENCODING = 'gbk'

DEBUG_PRINT = 0

def load_item_db(db_path):

    if not os.path.isfile(db_path):
        raise FaultError('item database:%s not found!' % db_path)

    data = codecs.open(db_path, encoding = DEFAULT_ENCODING).read()
    item_db = (None, None, None)
    try:
        item_db = parse_item_data(data)
    except ParseError,e:
        print repr(e)
    return item_db

def save_item_db(db_path, item_db, english_schema, chinese_schema):
    f = codecs.open(db_path, mode = 'wb', encoding = DEFAULT_ENCODING)
    # write author info
    f.write(u'//Author:%s %s\r\n' % (AUTHOR, time.ctime()))
    # write schema
    f.write(u'//%s\r\n' % u','.join(english_schema))
    f.write(u'//%s\r\n' % u','.join(chinese_schema))
    # write item
    ids = item_db.keys()
    ids.sort()
    for id in ids:
        item = item_db[id]
        f.write(u'%s\r\n' % u','.join(item))
    f.close()

def parse_item_data(data):

    lines = []
    for line in data.split(u'\r\n'):
        line = line.strip()
        if line:
            lines.append(line)
    
    stamp = lines[0]
    # ignore leading '//'
    english_schema = parse_schema(lines[1][2:])
    chinese_schema = parse_schema(lines[2][2:])
    assert len(english_schema) == len(chinese_schema)
    schema_pattern = build_schema_pattern(english_schema)
    
    item_entries = lines[3:]
    items = {}
    for entry in item_entries:
        m = schema_pattern.match(entry)
        if not m:
            raise ParseError('violating schema:\n%s' % entry)
            continue
        id = int(m.group('id'))
        if id in items:
            print 'duplicated id :%d, ignore:\n%s' % (id, entry)
            continue
        items[id] = Item(m.groups())
        assert len(items[id]) == len(english_schema)

    # future parse block data
    # ....

    # build ItemAttribute.EnglishChineseMap and Item.NameIdxMap
    for i in range(len(english_schema)):
        key = english_schema[i]
        val = chinese_schema[i]
        if key.startswith('{'):
            key = key[1:-1]
            val = val[1:-1]
        
        ItemAttribute.EnglishChineseMap[key] = val
        Item.NameIdxMap[key] = i 
    # build NameIdxMap
    return items, english_schema, chinese_schema

def parse_schema(data):
    return [ seg.strip().lower() for seg in data.split(u',')]

def build_schema_pattern(schema):
    pattern = []
    base_match_str_fmt = ur'(?P<%s>[^,\{\}]*)'
    block_match_str_fmt = ur'(?P<%s>\{.*\})'
    for attr in schema:
        fmt = base_match_str_fmt
        if attr.startswith(u'{'):
            attr = attr[1:-1]
            fmt = block_match_str_fmt
        body = fmt % attr
        pattern.append(body)
    pattern = u','.join(pattern)
    if DEBUG_PRINT:
        print 'pattern string is:\n%s' % pattern
    return re.compile(pattern, re.I)

class Item(list):

    NameIdxMap = {}
    def __getitem__(self, key):
        if isinstance(key, int):
            idx = key
        else:
            idx = self.NameIdxMap[key]
        return list.__getitem__(self, idx)

    def __setitem__(self, key, val):
        if isinstance(key, int):
            idx = key
        else:
            idx = self.NameIdxMap[key]
        return list.__setitem__(self, idx, val)
        
    
# create widget, return a widget, to hold attribue and exchange value
from Tkinter import *



class ItemAttribute:

    DEFAULT_FONT = ('Courier New', 12)
    EnglishChineseMap = {}
    CH = 1
    EN = 0
    Lang = CH
    ItemLabels = []
    
    def __init__(self, **kwds):

        self.host = None
        self.name = 'UnNamed attribute'
        self.row = None
        self.column = None
        
        for name in kwds:
            setattr(self, name, kwds[name])
            
    def bind(self, host):
        prev_host = self.host
        self.host = host
        return prev_host

    def release(self):
        host = self.host
        self.host = None
        return host

    def create_label(self, root):
        if self.row is None:
            raise AttributeError('arribute row not set!')
        if self.column is None:
            raise AttributeError('arribute column not set!')
        text = StringVar(root)
        text.set(self.get_label_name())
        label = Label(root, textvariable = text)
        label.grid(row = self.row, column = self.column, sticky = W, padx = 2, pady = 1)
        label['font'] = self.DEFAULT_FONT
        self.ItemLabels.append((text, self))
        return 1
    
    def create_attr_holder(self, root):
        value = Entry(root, textvariable = getattr(self.host, self.name), width = 14)
        value.grid(row = self.row, column = self.column, sticky = E + W)
        value['font'] = self.DEFAULT_FONT
        return 1
    
    # for attribute to override
    #def create_detail_dialogbox(self):
    
    def create_detail_button(self, root):
        
        btn = Button(root, text = '+')
        btn.grid(row = self.row, column = self.column, sticky = W, padx = 2, pady = 2)
        btn.grid_remove()
        if hasattr(self, 'create_detail_dialogbox'):
            btn.grid()
            btn['command'] = self.create_detail_dialogbox
        return 1

    def create_widget(self, root):
        
        column_delta = self.create_label(root)
        self.column += column_delta
        
        column_delta = self.create_attr_holder(root)
        self.column += column_delta
        # return the increasement delta of column

        column_delta = self.create_detail_button(root)
        self.column += column_delta
        
        return self.column

    def get_label_name(self):
        if self.Lang == self.CH:
            return self.EnglishChineseMap[self.name]
        return self.name
    
    @classmethod
    def switch_langauge(self):
        if ItemAttribute.Lang == ItemAttribute.CH:
            ItemAttribute.Lang = ItemAttribute.EN
        else:    
            ItemAttribute.Lang = ItemAttribute.CH
        self.update_label_text()

    @classmethod
    def update_label_text(self):
        for text, attr in self.ItemLabels:
            text.set(attr.get_label_name())
    

